import { LogType, saveLog } from "../utils/LogUtil";
import { getMaster } from "../utils/mirUtil";
import { randomInRange } from "../utils/utls"
import { getItemMangae, getSpecialMonManage } from "../系统功能/GlobalObjectManage";
import { Minute, MoneyEnum } from "../配置/基础配置"
import { MonItemMap } from "../配置/怪物爆率";

export interface MonItem { item: string, amount: number }

interface MonItemable {
    throwItem(Player: TPlayObject, reduceRate: number): MonItem[]
}

export class MonItemManage {
    monItemMap: Map<string, MonItemable[]>;
    belong: any;//怪物归属

    constructor() {
        this.monItemMap = new Map<string, MonItemable[]>();
        this.belong = GameLib.R.belong || {};
        GameLib.R.belong = this.belong;

        this.initMonItems();
    }

    onMonitorDie(Envir: TEnvirnoment, Monster: TActor, Killer: TActor, Tag: number): void {




        let Player: TPlayObject = null;
        let obj = this.belong[Monster.Handle]
        if (obj) {
            // console.log(obj)
            let ttt = GameLib.TickCount - obj.time;
            // console.log(`${Monster.Name}  ${ttt}`)
            if (ttt <= Minute) {
                Player = GameLib.FindPlayer(obj.name)
            }
        }

        delete this.belong[Monster.Handle]

        if (Player) {
            saveLog(`${Monster.Name}死亡 归属${Player.Name} `, LogType.Die)

            let name: string = MonItemMap[Monster.Name];
            if (name) {
                if (this.monItemMap.has(name)) {
                    let availableItems: MonItemable[] = this.monItemMap.get(name) || []
                    this.genThrowMonItem(Monster, Player, availableItems)
                }

            }
        }
    }

    //怪物最终受到伤害触发
    onMonDamage(boss: TActor, source: TActor, Value: number): void {
        if (boss.IsPlayer()) {
            return;
        }

        let play: TActor = getMaster(source);
        if (play.IsPlayer()) {
            let obj = this.belong[boss.Handle]
            if (obj) {
                // console.log(obj)
                let ttt = GameLib.TickCount - obj.time;
                // console.log(ttt)
                if (obj.name == play.Name) {
                    obj.time = GameLib.TickCount;
                }
                else if (ttt >= Minute) {
                    obj.name = play.Name;
                    obj.time = GameLib.TickCount;
                }
            }
            else {
                obj = {
                    name: play.Name,
                    time: GameLib.TickCount,
                }
                this.belong[boss.Handle] = obj;
            }
        }
    }
    /**
     * 初始化爆物数据
     */
    initMonItems() {
        const filelist = GameLib.ReadDirFiles(GameLib.Path + 'MonItems', '*.txt', true)
        for (let i = 0; i < filelist.GetCount(); i++) {
            const filename = filelist.GetStrings(i)
            const seps = filename.split('\\')
            const monster = seps[seps.length - 1].replace('.txt', '')
            const stringlist = GameLib.CreateStringList()
            stringlist.LoadFromFile(filename)
            // console.log(stringlist.Text)
            // logger.debug(filename, stringlist.Count)
            const lines: string[] = []
            for (let j = 0; j < stringlist.Count; j++) {
                lines.push(stringlist.GetStrings(j))
            }
            // logger.debug(lines)
            this.parseMonItem(monster, lines)
        }
        // logger.debug('加载爆率文件完成', filelist.GetCount(), MON_ITEM_MAP.size)
        filelist.Free()
    }

    parseMonItem(monster: string, lines: string[]) {
        if (lines.length == 0) {
            // logger.debug('爆率文件内容为空', monster)
            return
        }
        const monitems: MonItemable[] = []
        lines = lines
            .map(s => s.trim().replace('（', '(').replace('）', ')'))
            .filter(s => s.length > 0)

        let group = null
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i]
            // console.log(lines[i])
            const chars = line.split(/\s/).map(s => s.trim()).filter(s => s.length > 0)
            // console.log(chars)

            // start group
            if (line.startsWith('#G')) {
                const p = chars[1].split('/')
                const count = chars.length > 2 ? parseInt(chars[2]) : 1
                group = new MonItemGroup(parseInt(p[0]), parseInt(p[1]), [], count)
                continue
            }
            // start group item
            if (line.startsWith('(')) {
                continue
            }
            // end group
            if (line.startsWith(')') && group) {
                monitems.push(group)
                if (group.count > group.items.length) {
                    group.count = group.items.length
                }
                group = null
                continue
            }
            // build item
            const p = chars[0].split('/')
            const item = chars[1]
            if (item != '金币' && GameLib.FindItemIndex(item) < 0) {
                console.log(`加载爆率文件异常  ${monster}  ${item} `)
            }
            const amount = chars.length > 2 ? parseInt(chars[2]) : 1
            const monitem = new MonItemInfo(parseInt(p[0]), parseInt(p[1]), item, amount)

            // add group item
            if (group) {
                group.items.push(monitem)
                continue
            }
            // add normal item
            if (!group) {
                monitems.push(monitem)
                continue
            }
        }
        this.monItemMap.set(monster, monitems)
    }

    /**
     * 执行爆出物品
     * @param Monster 
     * @param Player 
     * @param availableItems 
     */
    genThrowMonItem(Monster: TActor, Player: TPlayObject, availableItems: MonItemable[]) {
        const allItems: MonItem[] = []
        for (let i = 0; i < availableItems.length; i++) {
            const throwItems = availableItems[i].throwItem(
                Player,
                1
            )
            allItems.push(...throwItems)
        }
        for (let i = 0; i < allItems.length; i++) {
            const g = allItems[i]
            // 会员自动捡金币
            // if (isMember(Player) && g.item.startsWith('金币')) {
            //     Player.AddGameMoney(MoneyEnum.Gold, g.amount, '自动捡金币')
            //     continue
            // }
            // const stdindex = GameLib.FindItemIndex(g.item)
            // const stdItem: TStdItem = GameLib.FindStdItem(stdindex)


            // 是否爆成功
            let ret = false
            let range = 2
            while (!ret && range < 100) {
                ret = GameLib.ThrowItemEx(Monster.Map, g.item, Monster.MapX, Monster.MapY, range, g.amount, Player, 120000)
                // 爆物失败，扩大范围
                if (!ret) {
                    range++
                }
            }
            // 爆物失败？
            if (!ret) {
                let str = `怪物${Monster.Name}在地图${Monster.Map.Name} (${Monster.MapX},${Monster.MapY})爆${g.item} 失败`
                saveLog(str, LogType.MonItemError, Monster, Player)
                continue
            }
            let flag = shouldBroadcast(g.item)
            let str = `${Monster.Map.Name} 的[${Monster.Name}]掉落物品：${g.item} `
            // 爆物提示
            if (shouldBroadcast(g.item)) {
                GameLib.Broadcast(`${Monster.Map.Name} 的[${clearNameNum(Monster.Name)}]掉落物品：${g.item} `)
            }

            let monset = getSpecialMonManage().getSpecialMonSet(Monster.Name)
            if (flag || monset) {
                saveLog(str, LogType.MonItem, Monster, Player)
            }
        }
    }
}


export class MonItemInfo implements MonItemable {
    /** 分子：1/10中的1 */
    public n: number
    /** 分母：1/10中的10 */
    public d: number
    public item: string
    public amount: number
    constructor(n: number, d: number, item: string, amount: number = 1) {
        this.n = n
        this.d = d
        this.item = item
        this.amount = amount
    }

    public throwItem(Player: TPlayObject, reduceRate: number): MonItem[] {

        // console.log(`${ this.item } ${ this.n } /${this.d}`)
        // 普通爆出（并且有库存）
        if (shouldThrow(this.n, this.d, Player, reduceRate)) {

            return [{ item: this.item, amount: this.amount }]
        }
        return []
    }
}


class MonItemGroup implements MonItemable {
    public n: number
    public d: number
    public items: MonItemInfo[]
    public count: number
    constructor(n: number, d: number, items: MonItemInfo[], count: number = 1) {
        this.n = n
        this.d = d
        this.count = count
        this.items = items
    }
    public throwItem(Player: TPlayObject, reduceRate: number): MonItem[] {
        const throwItems: MonItem[] = []

        // should throw group
        if (shouldThrow(this.n, this.d, Player, reduceRate)) {
            let item: MonItemInfo = this.items[randomInRange(this.items.length)]
            if (shouldThrow(item.n, item.d, Player, reduceRate)) {
                throwItems.push(item);
            }
        }
        return throwItems
    }
}

/**
 * 是否应该爆出
 * @param n 分子
 * @param d 分母
 * @param Player 玩家
 * @returns 
 */
const shouldThrow = (n: number, d: number, Player: TPlayObject, reduceRate: number) => {
    if (n == d) return true
    n = n * 1000
    d = d * 1000
    // console.log(Player.GetAddedAbility().GetItemRate())
    // 系统爆率倍数
    const prate = (Player.GetAddedAbility().GetItemRate() / 100) + 1
    if (prate && prate >= 0) {
        n = Math.floor(n * prate)
    } else {
        n = n
    }

    // 系统校正
    n = Math.floor(n * reduceRate)
    const randomN = randomRange(1, d + 1)
    const finnalN = Math.min(randomN, d)
    const ret = finnalN <= n
    // logger.debug(`爆出概率(${1}-${d})，当前倍数(${CurrentServerState.ExposeRate})：${n}/${d}, 结果：${finnalN}, ${ret ? '爆' : '不爆'}, 系统校正：${reduceRate}`)
    return ret
}

export function shouldBroadcast(itemName: string): boolean {
    let index = getItemMangae().getLvIndexByItemName(itemName);
    if (index >= 3) {
        return true;
    }

    return false;
}

/** 修复显示名称上的数字 */
export const clearNameNum = (Name: string) => {
    if (!Name) {
        return ''
    }
    let _Name = Name
    _Name = _Name.replace(/\d+/, '')
    return _Name
}


